// cmd/vmctl/commands/storage.go
package commands

import (
	"context"
	"encoding/json"
	"fmt"
	"strings"

	"github.com/sirupsen/logrus"
	"github.com/spf13/cobra"

	"virt-manager-go/internal/domain"
)

func NewStorageCommand(logger *logrus.Logger) *cobra.Command {
	cmd := &cobra.Command{
		Use:   "storage",
		Short: "Manage storage pools and volumes",
		Long:  "Create, manage, and delete storage pools and volumes",
	}

	cmd.AddCommand(
		newStoragePoolListCommand(logger),
		newStoragePoolCreateCommand(logger),
		newStoragePoolDeleteCommand(logger),
		newStorageVolumeListCommand(logger),
		newStorageVolumeCreateCommand(logger),
	)

	return cmd
}

// vmctl storage pool list
func newStoragePoolListCommand(logger *logrus.Logger) *cobra.Command {
	var connID string

	cmd := &cobra.Command{
		Use:   "pool-list",
		Short: "List storage pools",
		RunE: func(cmd *cobra.Command, args []string) error {
			apiClient := getAPIClient(logger)
			if connID == "" {
				connID = getDefaultConnection(apiClient)
			}

			ctx := context.Background()
			resp, err := apiClient.Get(ctx, fmt.Sprintf("/api/v1/connections/%s/storage/pools", connID))
			if err != nil {
				return err
			}

			var result struct {
				Data []domain.StoragePoolInfo `json:"data"`
			}
			if err := json.Unmarshal(resp, &result); err != nil {
				return err
			}

			// 获取输出格式并格式化输出
			outputFormat := GetOutputFormat(cmd.Flag("output").Value.String())
			formatter := NewFormatter(outputFormat)
			return formatter.FormatStoragePoolList(result.Data)
		},
	}

	cmd.Flags().StringVarP(&connID, "connection", "c", "", "Connection ID")
	return cmd
}

// vmctl storage pool-create
func newStoragePoolCreateCommand(logger *logrus.Logger) *cobra.Command {
	var (
		connID    string
		name      string
		poolType  string
		path      string
		autostart bool
	)

	cmd := &cobra.Command{
		Use:     "pool-create",
		Short:   "Create a storage pool",
		Example: `  vmctl storage pool-create --name mypool --type dir --path /var/lib/libvirt/mypool`,
		RunE: func(cmd *cobra.Command, args []string) error {
			apiClient := getAPIClient(logger)
			if connID == "" {
				connID = getDefaultConnection(apiClient)
			}

			config := domain.StoragePoolConfig{
				Name: name,
				Type: poolType,
				Target: &domain.PoolTargetConfig{
					Path: path,
				},
				Autostart: autostart,
			}

			ctx := context.Background()
			resp, err := apiClient.Post(ctx, fmt.Sprintf("/api/v1/connections/%s/storage/pools", connID), config)
			if err != nil {
				return err
			}

			var result struct {
				Data domain.StoragePoolInfo `json:"data"`
			}
			if err := json.Unmarshal(resp, &result); err != nil {
				return err
			}

			fmt.Printf("✓ Storage pool '%s' created\n", result.Data.Name)
			return nil
		},
	}

	cmd.Flags().StringVarP(&connID, "connection", "c", "", "Connection ID")
	cmd.Flags().StringVarP(&name, "name", "n", "", "Pool name (required)")
	cmd.Flags().StringVarP(&poolType, "type", "t", "dir", "Pool type (dir, nfs, iscsi)")
	cmd.Flags().StringVarP(&path, "path", "p", "", "Pool path (required)")
	cmd.Flags().BoolVar(&autostart, "autostart", true, "Autostart pool")

	cmd.MarkFlagRequired("name")
	cmd.MarkFlagRequired("path")

	return cmd
}

// vmctl storage pool-delete
func newStoragePoolDeleteCommand(logger *logrus.Logger) *cobra.Command {
	var (
		connID  string
		confirm bool
	)

	cmd := &cobra.Command{
		Use:   "pool-delete <pool-name>",
		Short: "Delete a storage pool",
		Args:  cobra.ExactArgs(1),
		RunE: func(cmd *cobra.Command, args []string) error {
			apiClient := getAPIClient(logger)
			if connID == "" {
				connID = getDefaultConnection(apiClient)
			}

			poolName := args[0]

			if !confirm {
				fmt.Printf("Delete storage pool '%s'? [y/N]: ", poolName)
				var response string
				fmt.Scanln(&response)
				if strings.ToLower(response) != "y" {
					return nil
				}
			}

			ctx := context.Background()
			_, err := apiClient.Delete(ctx, fmt.Sprintf("/api/v1/connections/%s/storage/pools/%s", connID, poolName))
			if err != nil {
				return err
			}

			fmt.Printf("✓ Storage pool '%s' deleted\n", poolName)
			return nil
		},
	}

	cmd.Flags().StringVarP(&connID, "connection", "c", "", "Connection ID")
	cmd.Flags().BoolVarP(&confirm, "yes", "y", false, "Skip confirmation")
	return cmd
}

// vmctl storage volume-list
func newStorageVolumeListCommand(logger *logrus.Logger) *cobra.Command {
	var connID string

	cmd := &cobra.Command{
		Use:   "volume-list <pool-name>",
		Short: "List volumes in a storage pool",
		Args:  cobra.ExactArgs(1),
		RunE: func(cmd *cobra.Command, args []string) error {
			apiClient := getAPIClient(logger)
			if connID == "" {
				connID = getDefaultConnection(apiClient)
			}

			poolName := args[0]
			ctx := context.Background()
			resp, err := apiClient.Get(ctx, fmt.Sprintf("/api/v1/connections/%s/storage/pools/%s/volumes", connID, poolName))
			if err != nil {
				return err
			}

			var result struct {
				Data []domain.StorageVolumeInfo `json:"data"`
			}
			if err := json.Unmarshal(resp, &result); err != nil {
				return err
			}

			// 获取输出格式并格式化输出
			outputFormat := GetOutputFormat(cmd.Flag("output").Value.String())
			formatter := NewFormatter(outputFormat)
			return formatter.FormatStorageVolumeList(result.Data)
		},
	}

	cmd.Flags().StringVarP(&connID, "connection", "c", "", "Connection ID")
	return cmd
}

// vmctl storage volume-create
func newStorageVolumeCreateCommand(logger *logrus.Logger) *cobra.Command {
	var (
		connID   string
		poolName string
		name     string
		size     uint64
		format   string
	)

	cmd := &cobra.Command{
		Use:     "volume-create",
		Short:   "Create a storage volume",
		Example: `  vmctl storage volume-create --pool default --name vm-disk.qcow2 --size 50 --format qcow2`,
		RunE: func(cmd *cobra.Command, args []string) error {
			apiClient := getAPIClient(logger)
			if connID == "" {
				connID = getDefaultConnection(apiClient)
			}

			config := domain.StorageVolumeConfig{
				Name:     name,
				Capacity: size * 1024 * 1024 * 1024, // GB to bytes
				Format:   format,
			}

			ctx := context.Background()
			resp, err := apiClient.Post(ctx,
				fmt.Sprintf("/api/v1/connections/%s/storage/pools/%s/volumes", connID, poolName),
				config)
			if err != nil {
				return err
			}

			var result struct {
				Data domain.StorageVolumeInfo `json:"data"`
			}
			if err := json.Unmarshal(resp, &result); err != nil {
				return err
			}

			fmt.Printf("✓ Volume '%s' created\n", result.Data.Name)
			return nil
		},
	}

	cmd.Flags().StringVarP(&connID, "connection", "c", "", "Connection ID")
	cmd.Flags().StringVarP(&poolName, "pool", "p", "", "Pool name (required)")
	cmd.Flags().StringVarP(&name, "name", "n", "", "Volume name (required)")
	cmd.Flags().Uint64VarP(&size, "size", "s", 0, "Size in GB (required)")
	cmd.Flags().StringVarP(&format, "format", "f", "qcow2", "Volume format (qcow2, raw)")

	cmd.MarkFlagRequired("pool")
	cmd.MarkFlagRequired("name")
	cmd.MarkFlagRequired("size")

	return cmd
}

// ============================================
// cmd/vmctl/commands/snapshot.go
// ============================================

func NewSnapshotCommand(logger *logrus.Logger) *cobra.Command {
	cmd := &cobra.Command{
		Use:   "snapshot",
		Short: "Manage VM snapshots",
		Long:  "Create, list, revert, and delete VM snapshots",
	}

	cmd.AddCommand(
		newSnapshotListCommand(logger),
		newSnapshotCreateCommand(logger),
		newSnapshotRevertCommand(logger),
		newSnapshotDeleteCommand(logger),
	)

	return cmd
}

// vmctl snapshot list <vm>
func newSnapshotListCommand(logger *logrus.Logger) *cobra.Command {
	var connID string

	cmd := &cobra.Command{
		Use:   "list <vm-name>",
		Short: "List VM snapshots",
		Args:  cobra.ExactArgs(1),
		RunE: func(cmd *cobra.Command, args []string) error {
			apiClient := getAPIClient(logger)
			if connID == "" {
				connID = getDefaultConnection(apiClient)
			}

			vmName := args[0]
			ctx := context.Background()
			resp, err := apiClient.Get(ctx, fmt.Sprintf("/api/v1/connections/%s/vms/%s/snapshots", connID, vmName))
			if err != nil {
				return err
			}

			var result struct {
				Data []domain.SnapshotInfo `json:"data"`
			}
			if err := json.Unmarshal(resp, &result); err != nil {
				return err
			}

			// 获取输出格式并格式化输出
			outputFormat := GetOutputFormat(cmd.Flag("output").Value.String())
			formatter := NewFormatter(outputFormat)
			return formatter.FormatSnapshotList(result.Data)
		},
	}

	cmd.Flags().StringVarP(&connID, "connection", "c", "", "Connection ID")
	return cmd
}

// vmctl snapshot create <vm> <name>
func newSnapshotCreateCommand(logger *logrus.Logger) *cobra.Command {
	var (
		connID      string
		description string
		memory      bool
		quiesce     bool
	)

	cmd := &cobra.Command{
		Use:   "create <vm-name> <snapshot-name>",
		Short: "Create a VM snapshot",
		Args:  cobra.ExactArgs(2),
		Example: `  vmctl snapshot create ubuntu-vm snap1 --description "Before update"
  vmctl snapshot create ubuntu-vm snap2 --memory --description "With RAM state"`,
		RunE: func(cmd *cobra.Command, args []string) error {
			apiClient := getAPIClient(logger)
			if connID == "" {
				connID = getDefaultConnection(apiClient)
			}

			vmName := args[0]
			snapName := args[1]

			config := domain.SnapshotConfig{
				Name:        snapName,
				Description: description,
				Memory:      memory,
				Quiesce:     quiesce,
			}

			ctx := context.Background()
			resp, err := apiClient.Post(ctx,
				fmt.Sprintf("/api/v1/connections/%s/vms/%s/snapshots", connID, vmName),
				config)
			if err != nil {
				return err
			}

			var result struct {
				Data domain.SnapshotInfo `json:"data"`
			}
			if err := json.Unmarshal(resp, &result); err != nil {
				return err
			}

			fmt.Printf("✓ Snapshot '%s' created for VM '%s'\n", result.Data.Name, vmName)
			return nil
		},
	}

	cmd.Flags().StringVarP(&connID, "connection", "c", "", "Connection ID")
	cmd.Flags().StringVarP(&description, "description", "d", "", "Snapshot description")
	cmd.Flags().BoolVar(&memory, "memory", false, "Include memory state")
	cmd.Flags().BoolVar(&quiesce, "quiesce", false, "Quiesce filesystem")
	return cmd
}

// vmctl snapshot revert <vm> <name>
func newSnapshotRevertCommand(logger *logrus.Logger) *cobra.Command {
	var connID string

	cmd := &cobra.Command{
		Use:   "revert <vm-name> <snapshot-name>",
		Short: "Revert VM to snapshot",
		Args:  cobra.ExactArgs(2),
		RunE: func(cmd *cobra.Command, args []string) error {
			apiClient := getAPIClient(logger)
			if connID == "" {
				connID = getDefaultConnection(apiClient)
			}

			vmName := args[0]
			snapName := args[1]

			ctx := context.Background()
			_, err := apiClient.Post(ctx,
				fmt.Sprintf("/api/v1/connections/%s/vms/%s/snapshots/%s/revert", connID, vmName, snapName),
				nil)
			if err != nil {
				return err
			}

			fmt.Printf("✓ Reverted VM '%s' to snapshot '%s'\n", vmName, snapName)
			return nil
		},
	}

	cmd.Flags().StringVarP(&connID, "connection", "c", "", "Connection ID")
	return cmd
}

// vmctl snapshot delete <vm> <name>
func newSnapshotDeleteCommand(logger *logrus.Logger) *cobra.Command {
	var (
		connID  string
		confirm bool
	)

	cmd := &cobra.Command{
		Use:   "delete <vm-name> <snapshot-name>",
		Short: "Delete a VM snapshot",
		Args:  cobra.ExactArgs(2),
		RunE: func(cmd *cobra.Command, args []string) error {
			apiClient := getAPIClient(logger)
			if connID == "" {
				connID = getDefaultConnection(apiClient)
			}

			vmName := args[0]
			snapName := args[1]

			if !confirm {
				fmt.Printf("Delete snapshot '%s' from VM '%s'? [y/N]: ", snapName, vmName)
				var response string
				fmt.Scanln(&response)
				if strings.ToLower(response) != "y" {
					return nil
				}
			}

			ctx := context.Background()
			_, err := apiClient.Delete(ctx,
				fmt.Sprintf("/api/v1/connections/%s/vms/%s/snapshots/%s", connID, vmName, snapName))
			if err != nil {
				return err
			}

			fmt.Printf("✓ Snapshot '%s' deleted\n", snapName)
			return nil
		},
	}

	cmd.Flags().StringVarP(&connID, "connection", "c", "", "Connection ID")
	cmd.Flags().BoolVarP(&confirm, "yes", "y", false, "Skip confirmation")
	return cmd
}

// ============================================
// cmd/vmctl/commands/batch.go
// ============================================

func NewBatchCommand(logger *logrus.Logger) *cobra.Command {
	cmd := &cobra.Command{
		Use:   "batch",
		Short: "Batch operations on multiple VMs",
		Long:  "Perform operations on multiple VMs simultaneously",
	}

	cmd.AddCommand(
		newBatchStartCommand(logger),
		newBatchStopCommand(logger),
		newBatchDeleteCommand(logger),
		newBatchSnapshotCommand(logger),
	)

	return cmd
}

// vmctl batch start <vm1> <vm2> ...
func newBatchStartCommand(logger *logrus.Logger) *cobra.Command {
	var connID string

	cmd := &cobra.Command{
		Use:     "start <vm-name>...",
		Short:   "Start multiple VMs",
		Args:    cobra.MinimumNArgs(1),
		Example: `  vmctl batch start vm1 vm2 vm3 vm4`,
		RunE: func(cmd *cobra.Command, args []string) error {
			apiClient := getAPIClient(logger)
			if connID == "" {
				connID = getDefaultConnection(apiClient)
			}

			req := map[string]interface{}{
				"vm_names": args,
			}

			ctx := context.Background()
			resp, err := apiClient.Post(ctx,
				fmt.Sprintf("/api/v1/connections/%s/batch/vms/start", connID),
				req)
			if err != nil {
				return err
			}

			var result struct {
				Data domain.BatchResult `json:"data"`
			}
			if err := json.Unmarshal(resp, &result); err != nil {
				return err
			}

			fmt.Printf("Batch operation completed:\n")
			fmt.Printf("  Total:      %d\n", result.Data.Total)
			fmt.Printf("  Successful: %d\n", result.Data.Successful)
			fmt.Printf("  Failed:     %d\n", result.Data.Failed)
			fmt.Printf("  Duration:   %s\n", result.Data.Duration)

			if result.Data.Failed > 0 {
				fmt.Println("\nFailed VMs:")
				for _, r := range result.Data.Results {
					if !r.Success {
						fmt.Printf("  - %s: %s\n", r.Target, r.Error)
					}
				}
			}

			return nil
		},
	}

	cmd.Flags().StringVarP(&connID, "connection", "c", "", "Connection ID")
	return cmd
}

// vmctl batch stop <vm1> <vm2> ...
func newBatchStopCommand(logger *logrus.Logger) *cobra.Command {
	var (
		connID string
		force  bool
	)

	cmd := &cobra.Command{
		Use:     "stop <vm-name>...",
		Short:   "Stop multiple VMs",
		Args:    cobra.MinimumNArgs(1),
		Example: `  vmctl batch stop vm1 vm2 vm3 --force`,
		RunE: func(cmd *cobra.Command, args []string) error {
			apiClient := getAPIClient(logger)
			if connID == "" {
				connID = getDefaultConnection(apiClient)
			}

			req := map[string]interface{}{
				"vm_names": args,
				"force":    force,
			}

			ctx := context.Background()
			resp, err := apiClient.Post(ctx,
				fmt.Sprintf("/api/v1/connections/%s/batch/vms/stop", connID),
				req)
			if err != nil {
				return err
			}

			var result struct {
				Data domain.BatchResult `json:"data"`
			}
			if err := json.Unmarshal(resp, &result); err != nil {
				return err
			}

			fmt.Printf("✓ Batch stop completed: %d/%d successful\n",
				result.Data.Successful, result.Data.Total)
			return nil
		},
	}

	cmd.Flags().StringVarP(&connID, "connection", "c", "", "Connection ID")
	cmd.Flags().BoolVarP(&force, "force", "f", false, "Force stop")
	return cmd
}

// vmctl batch delete <vm1> <vm2> ...
func newBatchDeleteCommand(logger *logrus.Logger) *cobra.Command {
	var (
		connID        string
		removeStorage bool
		confirm       bool
	)

	cmd := &cobra.Command{
		Use:   "delete <vm-name>...",
		Short: "Delete multiple VMs",
		Args:  cobra.MinimumNArgs(1),
		RunE: func(cmd *cobra.Command, args []string) error {
			apiClient := getAPIClient(logger)
			if connID == "" {
				connID = getDefaultConnection(apiClient)
			}

			if !confirm {
				fmt.Printf("Delete %d VMs? [y/N]: ", len(args))
				var response string
				fmt.Scanln(&response)
				if strings.ToLower(response) != "y" {
					return nil
				}
			}

			req := map[string]interface{}{
				"vm_names":       args,
				"remove_storage": removeStorage,
			}

			ctx := context.Background()
			resp, err := apiClient.Post(ctx,
				fmt.Sprintf("/api/v1/connections/%s/batch/vms/delete", connID),
				req)
			if err != nil {
				return err
			}

			var result struct {
				Data domain.BatchResult `json:"data"`
			}
			if err := json.Unmarshal(resp, &result); err != nil {
				return err
			}

			fmt.Printf("✓ Batch delete completed: %d/%d successful\n",
				result.Data.Successful, result.Data.Total)
			return nil
		},
	}

	cmd.Flags().StringVarP(&connID, "connection", "c", "", "Connection ID")
	cmd.Flags().BoolVar(&removeStorage, "remove-storage", false, "Remove storage")
	cmd.Flags().BoolVarP(&confirm, "yes", "y", false, "Skip confirmation")
	return cmd
}

// vmctl batch snapshot <vm1> <vm2> ... --name <snap-name>
func newBatchSnapshotCommand(logger *logrus.Logger) *cobra.Command {
	var (
		connID      string
		snapName    string
		description string
	)

	cmd := &cobra.Command{
		Use:     "snapshot <vm-name>...",
		Short:   "Create snapshots for multiple VMs",
		Args:    cobra.MinimumNArgs(1),
		Example: `  vmctl batch snapshot vm1 vm2 vm3 --name backup-2025`,
		RunE: func(cmd *cobra.Command, args []string) error {
			apiClient := getAPIClient(logger)
			if connID == "" {
				connID = getDefaultConnection(apiClient)
			}

			req := map[string]interface{}{
				"vm_names": args,
				"config": domain.SnapshotConfig{
					Name:        snapName,
					Description: description,
					Memory:      false,
					DiskOnly:    true,
				},
			}

			ctx := context.Background()
			resp, err := apiClient.Post(ctx,
				fmt.Sprintf("/api/v1/connections/%s/batch/snapshots/create", connID),
				req)
			if err != nil {
				return err
			}

			var result struct {
				Data domain.BatchResult `json:"data"`
			}
			if err := json.Unmarshal(resp, &result); err != nil {
				return err
			}

			fmt.Printf("✓ Batch snapshot completed: %d/%d successful\n",
				result.Data.Successful, result.Data.Total)
			return nil
		},
	}

	cmd.Flags().StringVarP(&connID, "connection", "c", "", "Connection ID")
	cmd.Flags().StringVarP(&snapName, "name", "n", "", "Snapshot name (required)")
	cmd.Flags().StringVarP(&description, "description", "d", "", "Description")

	cmd.MarkFlagRequired("name")
	return cmd
}

// === 辅助函数 ===
// formatBytes 函数已移至 output.go 中
